package Connector;

import Connector.Processor.ServletProcessor;
import Connector.Processor.StaticProcessor;

import javax.servlet.ServletResponse;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import static Connector.ConnectorUtils.WEB_ROOT;

public class Connector implements Runnable {

    private static final int DEFAULT_PORT = 8888;
    // static final 相当于C语言的 const

    private int port;

    private ServerSocket server;
    // TODO 为什么不直接初始化?
        // 没有办法关闭

    // 如果不传参数，那么就是8888；如果传参数，就指定了新的端口；
    // 无参数的构造方法
    public Connector() {
        this(DEFAULT_PORT);
        // this就是下面的重载的构造方法
    }
    // 有参数的构造方法
    public Connector(int port) {
        this.port = port;
    }
    // TODO 构造方法的重载，this()的使用

    // 启动一个connector线程
    // TODO 理论上tomcat是一个engine和多个connector； 这里有必要用线程吗?
    public void start(){
        Thread thread = new Thread(this);
        thread.start();
        // TODO 这里实现了并发处理吗???
            // 我认为没有。就一个线程啊。

        System.out.println("Connector thread is started.");
    }

    @Override
    public void run() {
        try {
            System.out.println("Connector thread is running.");

            server = new ServerSocket(port);
            // ServerSocket来实现对指定IP和指定端口的监听。

            System.out.println("*** The server is online, listening at port:" + port + " ***");
            System.out.println("*** the server resource: " + WEB_ROOT + " ***");

            // 开始自旋
            while (true){
                System.out.println("Connector thread starts Socket.");
                System.out.println("Socket is listening...");

                // 调用 ServerSocket 对象的 accept() 等待客户端socket的连接请求
                // 一旦监听到客户端的套接字请求，就会返回一个表示连接已建立的 Socket 对象，可以从中获取到输入流和输出流
                Socket socket = server.accept();
                // 这个socket会一直在这里等待，
                // socket运行期间，其他客户端无法建立新的socket，称为阻塞式

                System.out.println("Socket receives message.");

                InputStream input = socket.getInputStream();
                OutputStream output = socket.getOutputStream(); // TODO 不用关掉吗?

                System.out.println("Connector generates Request.");

                Request request = new Request(input);
                request.parse();

                System.out.println("Connector generates Response.");

                Response response = new Response(output);
                response.setRequest(request);

                if (request.getRequestURI().startsWith("/servlet/")){
                    System.out.println("Connector calls ServletProcessor.");

                    ServletProcessor processor = new ServletProcessor();
                    processor.process(request, response);
                } else {
                    System.out.println("Connector calls StaticProcessor.");

                    StaticProcessor processor = new StaticProcessor();
                    processor.process(request, response);
                }

                close(socket);

                System.out.println("Socket is closed.\r\n"); // /r/n是换行
                // TODO socket从来没有关闭过???
            }
        } catch (IOException e) {
            e.printStackTrace();
            // 不要记录了异常又抛出了异常；画蛇添足
        } finally {
            // 关闭serverSocket
            close(server);
            // TODO 为什么要自定义关闭方法? socket serverSocket自己没有吗?
        }
    }
    // 传统的资源关闭方式是使用try-catch-finally，在finally中关闭资源;
    // TODO 这里可以使用try-with-resource吗???
    // TODO socket
        // Socket是一个抽象概念，一个应用程序通过一个Socket来建立一个远程连接，而Socket内部通过TCP/IP协议把数据传输到网络：
        // Socket、TCP和部分IP的功能都是由操作系统提供的，不同的编程语言只是提供了对操作系统调用的简单的封装。例如，Java提供的几个Socket相关的类就封装了操作系统提供的接口。


    // 关闭socket serverSocket
    public void close(Closeable closeable){
        // TODO 为什么是Closeable???
        // 因为socket和serverSocket都继承了Closeable接口，可以用Closeable引用指向它们的对象
        if (closeable != null){
            try{
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
